# numpy像是一个列表，通过索引0~n进行访问

# pandas更像是一个字典形式的numpy，pandas更像是一个中文中的列表，有行头，有列头，可以通过行索引或者列索引获取数据

# 导入模块
import pandas as pd
import numpy as np

# 定义一个序列
s = pd.Series([1, 3, 5, 6, np.nan, 1])
print(s)

dates = pd.date_range('20210101', periods=8)
print(dates)

# 定义一个8行4列的列表，行头为index指定的内容，列头为colums指定的内容
# random是一个比较复杂的函数，功能比较多，randn只是其中一个，randn生成的数据符合正态分布
df = pd.DataFrame(np.random.randn(8, 4), index=dates,
                  columns=['a', 'b', 'c', 'd'])
print(df)

# 默认的行列索引从0开始，0，1，2，3等
df1 = pd.DataFrame(np.arange(12).reshape((3, 4)))
print(df1)

# 生成一个4行6列的列表，并能按列自动补全
df2 = pd.DataFrame({'A': 1, 'B': pd.Timestamp('20210814'), 'C': pd.Series(1, index=list(range(4)), dtype='float32'),
                    'D': np.array([3] * 4, dtype='int32'), 'E': pd.Categorical(['test', 'train', 'trans', 'text']),
                    'F': 'foo'})
print(df2)
print(df2.dtypes)
# 输出每一行的行索引
print(df2.index)
# 输出列索引
print(df2.columns)
# 输出所有值
print(df2.values)
# 输出df2的计算数据，平均值、最大值、最小值等，只会计算数字形式的数据
print(df2.describe())
# 输出df2的转置
print(df2.T)
# 排序，axis=1对列头排序，ascending=False逆序
print(df2.sort_index(axis=1, ascending=False))
# 对行头进行排序
print(df2.sort_index(axis=0, ascending=False))
# 按值进行排序
print(df2.sort_values(by='E'))

# pandas选择数据

# 定义一个日期序列，从起始位置递增，长度为6
dates = pd.date_range('20210801', periods=6)
# 定义一个6*4的列表，行头为dates内容，列头为A，B，C，D
df = pd.DataFrame(np.arange(24).reshape((6, 4)),
                  index=dates, columns=['A', 'B', 'C', 'D'])
print(df)

# 打印列
print(df.A)
print(df['A'])

# 打印指定行
# 左闭右开
print(df[0:3])
# 左右都闭
print(df['20210801':'20210803'])

# loc使用标签进行选择
# 打印指定行
print(df.loc['20210801'])
# 打印指定列列
print(df.loc[:, ['A', 'B']])
# 打印指定行和列
print(df.loc['20210801', ['A', 'B']])

# iloc使用位置进行选择
# 打印第三行
print(df.iloc[3])
# 打印第三行第一位
print(df.iloc[3, 1])
# 打印切片，切片是左闭右开
print(df.iloc[1:3, 1:3])
# 逐个打印
print('逐个打印：', df.iloc[[1, 2, 3], 3])

# ix使用标签和位置（数字）进行选择，新版pandas取消了ix
# 打印前3行和A、C两列
# print(df.ix[:3,['A','C']])

# 条件选择
# 打印A这一列的值大于8的所有行，有点SQL的味道
print(df[df.A > 8])

# 设置值

# 定义一个日期序列，从起始位置递增，长度为6
dates = pd.date_range('20210801', periods=6)
# 定义一个6*4的列表，行头为dates内容，列头为A，B，C，D
df = pd.DataFrame(np.arange(24).reshape((6, 4)),
                  index=dates, columns=['A', 'B', 'C', 'D'])
print(df)

# 修改元素值，需要先选择到数据
df.iloc[1, 1] = 100
print(df)

# 根据上一节的选择数据，选择到之后可以修改，可以修改多个或一个
# 将A列中所有大于8的元素改为8，以下两种方式都可以
df.loc[df.A > 8, 'A'] = 8
print(df)
df.A[df.A > 7] = 7
print(df)
# 修改匹配行的所有列
df[df.A > 6] = 6
print(df)

# 添加新的列
df['E'] = np.nan
print(df)
# 也可以添加不为空的值，添加一个序列并且索引对齐
df['F'] = pd.Series([1, 2, 3, 4, 5, 6],
                    index=pd.date_range('20210801', periods=6))
print(df)

# 处理丢失数据
# 定义一个日期序列，从起始位置递增，长度为6
dates = pd.date_range('20210801', periods=6)
# 定义一个6*4的列表，行头为dates内容，列头为A，B，C，D
df = pd.DataFrame(np.arange(24).reshape((6, 4)),
                  index=dates, columns=['A', 'B', 'C', 'D'])
df.iloc[0, 1] = np.nan
df.iloc[1, 2] = np.nan
print(df)

# 丢掉缺失值,how={'any','all'}，any表示这一行中有任意一个值为nan则删除这一行，all表示这一行所有值均为nan才删除这一行
print(df.dropna(axis=0, how='any'))

# 判断是否有丢失值
print(df.isnull())

# 给nan值填充数据
print(df.fillna(value=0))

# 判断是否至少有一个丢失值
print(np.any(df.isnull() == True))

# pandas导入和导出
# 读取
data = pd.read_csv('student.csv')
# 输出
print(data)

# pandas的concat合并
# 定义一个DataFrame
df1 = pd.DataFrame(np.ones((3, 4)) * 0, columns=['a', 'b', 'c', 'd'])
df2 = pd.DataFrame(np.ones((3, 4)) * 1, columns=['a', 'b', 'c', 'd'])
df3 = pd.DataFrame(np.ones((3, 4)) * 2, columns=['a', 'b', 'c', 'd'])
print(df1)
print(df2)
print(df3)

# concatenating
# 纵向合并，行的长度不变，行数增加，索引依然是原来的0，1，2
vres = pd.concat([df1, df2, df3], axis=0)
print(vres)
# 改变索引为连续值
vres = pd.concat([df1, df2, df3], axis=0, ignore_index=True)
print(vres)

# join，['inner','outer']
# 外连接，和SQL很相似，列取并集，列不对应的使用nan填充
df2 = pd.DataFrame(np.ones((3, 3)) * 1, columns=['a', 'b', 'c'])
print(pd.concat([df1, df2], join='outer'))
# 内连接，列取交集
print('内连接')
print(pd.concat([df1, df2], join='inner', ignore_index=True))

# append追加，纵向
print('追加')
print(df1.append(df3, ignore_index=True))
s1 = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
print(df1.append(s1, ignore_index=True))

# pandas的merge合并

# 定义一个DataFrame
left = pd.DataFrame({'A': ['A1', 'A2', 'A3', 'A4'],
                     'B': ['B1', 'B2', 'B3', 'B4'],
                     'key': ['K1', 'K2', 'K3', 'K4']})
right = pd.DataFrame({'C': ['C1', 'C2', 'C3', 'C4'],
                      'D': ['D1', 'D2', 'D3', 'D4'],
                      'key': ['K1', 'K2', 'K3', 'K4']})

print(left)
print(right)

# 根据key值进行合并，不相同的不合并，类似于SQL中的join，自然连接
print('根据key值进行合并')
print(pd.merge(left, right, on='key'))

# 考虑两个key值合并
left = pd.DataFrame({'A': ['A1', 'A2', 'A3', 'A4'],
                     'B': ['B1', 'B2', 'B3', 'B4'],
                     'key1': ['K1', 'K1', 'K2', 'K3'],
                     'key2': ['K1', 'K2', 'K1', 'K4']})
right = pd.DataFrame({'C': ['C1', 'C2', 'C3', 'C4'],
                      'D': ['D1', 'D2', 'D3', 'D4'],
                      'key1': ['K4', 'K1', 'K2', 'K3'],
                      'key2': ['K1', 'K1', 'K3', 'K4']})
print(pd.merge(left, right, on=['key1', 'key2']))

# indicator参数
print(pd.merge(left, right, on='key1', how='outer', indicator=True))
# indicator改名
print(pd.merge(left, right, on='key1', how='outer', indicator='indicator_merge'))

# index参数
left = pd.DataFrame({'A': ['A1', 'A2'],
                     'B': ['B1', 'B2']}, index=['K0', 'K1'])
right = pd.DataFrame({'C': ['C1', 'C2'],
                      'D': ['D1', 'D2']}, index=['K1', 'K2'])
print(left)
print(right)

# 使用index参数，根据index参数合并
print(pd.merge(left, right, left_index=True, right_index=True, how='outer'))
print(pd.merge(left, right, left_index=True, right_index=True, how='inner'))

# pandas图表
import matplotlib.pyplot as plt

# 生成序列
data = pd.Series(np.random.randn(1000), index=np.arange(1000))
# 累加计算
date = data.cumsum
# 输入数据
data.plot()
# 展示结果
plt.show()

# 生成列表DataFrame，1000个数据四个属性，1000行4列
data = pd.DataFrame(np.random.randn(1000, 4),
                    index=np.arange(1000),
                    columns=list("ABCD"))
data = data.cumsum()
print(data.head())
data.plot()
# 需要放在plt.show前，因为plt.show之后会生成一张空白画布，生成svg，然后再转化成emf（矢量图）格式插入到word中
plt.savefig("text.svg", dpi=600, format="svg")
plt.show()
